﻿// //  ********************************************************************************
// //  Copyright (C) 2016 Sebastian Kenter. All rights reserved.
// // 
// //  Name    : PhotonServerProject | LoginServer | AccountRegisterRequestHandler.cs
// //  Created : 2016 - 04 - 07 16:40
// //  Modified: 2016 - 04 - 18 09:38
// //  ********************************************************************************

using System;
using ExitGames.Logging;
using NHibernate;
using PhotonServerCommon;
using PhotonServerCommon.Entities.Domain;
using PhotonServerCommon.Enums;
using PhotonServerCommon.Messages;
using PhotonServerCommon.Messages.Helper;
using PhotonServerFramework.Implementation.Database;
using PhotonServerFramework.Implementation.Server;
using PhotonServerFramework.Implementation.Telegram;
using PhotonServerFramework.Interfaces.Handler;
using PhotonServerFramework.Interfaces.Server;
using PhotonServerFramework.Interfaces.Telegram;

namespace LoginServer.Handler.Request
{
    public class AccountRegisterRequestHandler : IServerTelegramHandler<IServerPeer>
    {
        public ILogger Logger { get; }
        public Guid HandlerId { get; set; } = Guid.NewGuid();
        public HandlerTypes HandlerType => HandlerTypes.Request;
        public byte HandlerCode => (byte) OperationCodes.Account;
        public int HandlerSubCode => (int) OperationSubCodes.RegisterAccount;

        public AccountRegisterRequestHandler(ILogger logger)
        {
            Logger = logger;
        }

        public bool HandleTelegram(ITelegram telegram, IServerPeer serverPeer)
        {
            bool handled = false;

            Logger.InfoFormat("Trying to handle telegram of type={0} with code={1}, subcode={2}", telegram.Type,
                (OperationCodes) telegram.TelegramCode, (OperationSubCodes) telegram.TelegramSubCode);

            ServerPeer peer = serverPeer as ServerPeer;
            AccountT account = null;

            AccountRegisterMessage message =
                MessageSerializer.DeserializeMessage<AccountRegisterMessage>(
                    (byte[]) telegram.TelegramParameters[(byte) ParameterCodes.AccountRegisterMessage]);

            if (message != null)
            {
                if (peer != null)
                {
                    using (ISession session = SessionManager.OpenSession())
                    {
                        using (ITransaction transaction = session.BeginTransaction())
                        {
                            try
                            {
                                account =
                                    session.QueryOver<AccountT>()
                                        .Where(c => c.AccountName == message.LoginName)
                                        .SingleOrDefault();
                                transaction.Commit();
                            }
                            catch (Exception ex)
                            {
                                Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                                transaction.Rollback();
                            }
                        }

                        if (account == null)
                        {
                            Logger.InfoFormat("No account found for login name: {0} - Inserting new one.",
                                message.LoginName);
                            byte[] salt = Pwdtk.GetRandomSalt();
                            byte[] hash = Pwdtk.PasswordToHash(salt, message.LoginPassword);

                            Logger.Debug(salt);
                            Logger.Debug(Pwdtk.HashBytesToHexString(salt));
                            Logger.Debug(hash);
                            Logger.Debug(Pwdtk.HashBytesToHexString(hash));

                            account = new AccountT
                                      {
                                          AccountId = Guid.NewGuid().ToString(),
                                          RemoteIp =
                                              telegram.TelegramParameters[(byte) ParameterCodes.ClientPeerIp].ToString(),
                                          AccountName = message.LoginName,
                                          GivenName = message.GivenName,
                                          Surname = message.SureName,
                                          Email = message.LoginName,
                                          Language = "DE",
                                          Region = 0,
                                          LoginFailures = 0,
                                          DzIns = DateTime.Now,
                                          DzUpd = DateTime.Now,
                                          NamUpd = GetType().Name,
                                          Tsn = 1,
                                          PasswordHash = Pwdtk.HashBytesToHexString(hash),
                                          Salt = Pwdtk.HashBytesToHexString(salt),
                                          Banned = 0,
                                          LoggedIn = 0,
                                          ClientPeerId =
                                              telegram.TelegramParameters[(byte) ParameterCodes.ClientPeerId].ToString()
                                      };

                            using (ITransaction transaction = session.BeginTransaction())
                            {
                                try
                                {
                                    session.Save(account);
                                    transaction.Commit();
                                    peer.SendTelegram(
                                        new ResponseTelegram
                                        {
                                            TelegramCode = telegram.TelegramCode,
                                            TelegramSubCode = telegram.TelegramSubCode,
                                            TelegramParameters = telegram.TelegramParameters,
                                            ReturnCode = (short) ErrorCodes.AccountRegistered,
                                            DebugMessage =
                                                EnumHelper.GetEnumDescription(
                                                    ErrorCodes.AccountRegistered)
                                        });
                                }
                                catch (Exception ex)
                                {
                                    Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                                    transaction.Rollback();
                                }
                            }
                        }
                        else
                        {
                            Logger.ErrorFormat("Account exists for login name: {0}", message.LoginName);
                            peer.SendTelegram(
                                new ResponseTelegram
                                {
                                    TelegramCode = telegram.TelegramCode,
                                    TelegramSubCode = telegram.TelegramSubCode,
                                    TelegramParameters = telegram.TelegramParameters,
                                    ReturnCode = (short) ErrorCodes.AccountExists,
                                    DebugMessage =
                                        EnumHelper.GetEnumDescription(
                                            ErrorCodes.AccountExists)
                                });
                        }

                        session.Close();
                    }
                }
                else
                {
                    Logger.ErrorFormat("Server peer invalid - cannot process telegram.");
                }

                handled = true;
            }
            else
            {
                Logger.ErrorFormat("Message invalid - cannot process telegram.");
            }

            return handled;
        }
    }
}
